object Liste { 
  def main ( ) : Unit = {
    println(new Main().Main());
  }
}

class Main {
    var ret:Bool;
    var list:List;
  def Main():String={
    list=new List();
    ret=list.init();

    ret=list.add(4);
    ret=list.add(8);
    ret=list.add(2);
    println(list.toString());
    println("size : " + list.size());
    ret=this.remove(4);
    println(list.toString());
    println("size : " + list.size());
    ret=this.remove(10);
    println(list.toString());
    println("size : " + list.size());
    ret=list.add(42);
    ret=list.add(51);
    ret=list.add(39);
    println(list.toString());
    println("size : " + list.size());
    println(list.get(4));

    return "end";
  }

  def remove(val:Int):Bool={//remove and print info
    println("remove "+val);
    ret=list.remove(val);
    if(ret) println("sucess"); else println("not in the list");
    return ret;
  }
}


class List extends Node{// class Node is a bit useless, but it was to use inheritance and overriding
  var value:Int;

  def init():Bool={//the head of the list has no value, and don't really exist. It's just to avoid to change the pointer when we remove the first element
    isFirst=true;
    notNil=true;
    n=new List();
    notNil=n.setprev(this);
    return true;
  }
  

  def add(val:Int):Bool={
    var useless:Bool;
    if(!notNil) { //= if Nil
      value=val;
      n=new List();
      useless=n.setprev(this);
      notNil=true;     
    } 
    else{
      useless=n.add(val);
    }
    return true;
  }

  def size():Int={
    var ret:Int;
    var node:Node;
    node=this;
    ret =0;
    while (node.isnotNil()){
      ret = ret+1;
      node=node.getnext();    
    }
    return ret-1;
  }

  def get(num:Int):Int={// 
    var i:Int;
    var node:Node;
    node=this;
    i = 0-1;
    while (!(i==num) && notNil){
      node=node.getnext();  
      i=i+1;
    }
    if(!node.isnotNil()) node=node.getnext(); //this line throw an exception if we outbound the list
    return node.getval();
  }

  def remove(val:Int):Bool={//return false if val is not in the list
    var ret:Bool;
    if(value==val && !isFirst && notNil){
      ret=p.setnext(n);
      ret=n.setprev(p);
    } 
    else if(notNil) {
      ret=n.remove(val);
    }
    else {
      ret=false;
    }
    return ret;
  }
  def setvalue(val:Int):Bool={
    value=val;
    return false;
  }
  def getval():Int={
    return value;
  }
  def toString():String={
    var s:String;
    s="";
    if(notNil){
      if(isFirst) s=n.toString();
      else s=s+value+" "+n.toString();
    }
    return s;
  }

}

class Node {
  var n:Node;
  var p:Node;
  var notNil: Bool;// because false is default value, flase==null and true==not null
  var isFirst:Bool;

  def getnext ():Node ={
    return n;
  }
  def getprev ():Node ={
    return p;
  }
  def setnext (ni:Node):Bool ={
    n=ni;
    return true;
  }
  def setprev (ni:Node):Bool ={
    p=ni;
    return true;
  }
  def isnotNil ():Bool = {
    return notNil;
  }
  def getLast():Node = {
    var r:Node;
    if(!notNil){
      r=this;
    }else{
      r=n.getLast();
    }
    return r;
  }
  def getval():Int={//abstract
    return 0;
  }
  def add(val:Int):Bool={// abstract
    return false;
  }
  def remove(val:Int):Bool={return false;}// abstract
  def toString():String={return "";}// abstract
}
